package cn.net.dpi.lock.support;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.IdGenerator;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotBlank;
import java.util.concurrent.TimeUnit;

/**
 * 基于 Redis 实现的分布式锁
 *
 * @author dangzhicairang
 */
@Validated
public class RedisLock extends AbstractLock {

    private StringRedisTemplate stringRedisTemplate;
    private IdGenerator idGenerator;

    public RedisLock(StringRedisTemplate stringRedisTemplate) {
        this(stringRedisTemplate, new AlternativeJdkIdGenerator());
    }

    public RedisLock(StringRedisTemplate stringRedisTemplate, IdGenerator idGenerator) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.idGenerator = idGenerator;
    }

    public StringRedisTemplate getStringRedisTemplate() {
        return stringRedisTemplate;
    }

    public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    public IdGenerator getIdGenerator() {
        return idGenerator;
    }

    public void setIdGenerator(IdGenerator idGenerator) {
        this.idGenerator = idGenerator;
    }

    @Override
    protected String doAcquire(@NotBlank String lockId, Integer expire) {
        String lock = idGenerator.generateId().toString();
        Boolean result = stringRedisTemplate.opsForValue()
                .setIfAbsent(lockId, lock, expire, TimeUnit.SECONDS);
        return result ? lock : null;
    }

    @Override
    public boolean release(@NotBlank String lockId, @NotBlank String lock) {
        String value = stringRedisTemplate.opsForValue()
                .get(lockId);
        if (StringUtils.hasLength(value) && value.equals(lock)) {
            stringRedisTemplate.delete(lockId);
            return true;
        }
        return false;
    }
}
